package com.lyf.scm.plan.domain.service.impl;

import com.lyf.scm.common.enums.OtherTargetsEnum;
import com.lyf.scm.common.enums.SkuUnitTypeEnum;
import com.lyf.scm.plan.api.dto.OtherTargetEchartResultDTO;
import com.lyf.scm.plan.api.dto.OtherTargetGeneralQueryDTO;
import com.lyf.scm.plan.api.dto.OtherTargetResultDTO;
import com.lyf.scm.plan.api.dto.UnitRateQueryDTO;
import com.lyf.scm.plan.domain.remote.item.dto.SkuUnitDTO;
import com.lyf.scm.plan.domain.service.*;
import com.lyf.scm.plan.domain.util.strategy.OtherTargetContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.FutureTask;


/**
 * 其它指标通用处理类
 *
 * @author wangchlei
 * @date 2020/11/12
 */
@Slf4j
@Service
public class OtherTargetGeneralServiceImpl implements OtherTargetGeneralService {
    @Resource
    private ExecutorService sonExecutorService;
    @Resource
    private ActualSalesQtyService actualSalesQtyService;
    @Resource
    private RealTimeStockService realTimeStockService;
    @Resource
    private PurchaseTargetService purchaseTargetService;
    @Resource
    private UrgentReplishmentService urgentReplishmentService;
    @Resource
    private ActualQtyService actualQtyService;
    @Resource
    private ActualStorageQtyService actualStorageQtyService;
    @Resource
    private RedisCacheService redisCacheService;

    /**
     * 列表其它指标获取
     *
     * @param otherTargetGeneralQuery
     * @return {@link List<OtherTargetResultDTO>}
     **/
    @Override
    public List<OtherTargetResultDTO> getNecessaryOtherTargets(OtherTargetGeneralQueryDTO otherTargetGeneralQuery) {
        List<OtherTargetResultDTO> otherTargetResultList = new ArrayList<>();
        List<OtherTargetsEnum> otherTargetsEnums = otherTargetGeneralQuery.getOtherTargetsEnum();
        List<FutureTask<OtherTargetResultDTO>> futureTasks = new ArrayList<>();
        //获取sku单位转换率 基础单位转其它单位
        Map<String, BigDecimal> unitMap = this.getUnitConversion(otherTargetGeneralQuery);
        //批量指标
        List<FutureTask<List<OtherTargetResultDTO>>> multiFutureTasks = new ArrayList<>();
        for (OtherTargetsEnum otherTargetsEnum : otherTargetsEnums) {
            if (OtherTargetsEnum.ACTUAL_SALES == otherTargetsEnum) {
                OtherTargetContext otherTargetContext = new OtherTargetContext(actualSalesQtyService);
                futureTasks.add(this.getAndExecuteFutureTask(otherTargetContext, otherTargetGeneralQuery, unitMap));
                continue;
            }
            if (OtherTargetsEnum.REAL_TIME_STOCK == otherTargetsEnum) {
                OtherTargetContext otherTargetContext = new OtherTargetContext(realTimeStockService);
                futureTasks.add(this.getAndExecuteFutureTask(otherTargetContext, otherTargetGeneralQuery,unitMap));
                continue;
            }
            //实际到仓库
            if (OtherTargetsEnum.ACTUAL_QTY == otherTargetsEnum) {
                OtherTargetContext otherTargetContext = new OtherTargetContext(actualQtyService);
                futureTasks.add(this.getAndExecuteFutureTask(otherTargetContext, otherTargetGeneralQuery,unitMap));
                continue;
            }
            //实际入库
            if (OtherTargetsEnum.ACTUAL_STORAGE_QTY == otherTargetsEnum) {
                OtherTargetContext otherTargetContext = new OtherTargetContext(actualStorageQtyService);
                futureTasks.add(this.getAndExecuteFutureTask(otherTargetContext, otherTargetGeneralQuery,unitMap));
                continue;
            }
            if (OtherTargetsEnum.BATCH_PURCHASE_ORDER_TARGET == otherTargetsEnum) {
                OtherTargetContext otherTargetContext = new OtherTargetContext(purchaseTargetService);
                multiFutureTasks.add(this.getMultiAndExecuteFutureTask(otherTargetContext, otherTargetGeneralQuery,unitMap));
                continue;
            }
            if (OtherTargetsEnum.TI_SS_STOCK == otherTargetsEnum) {
                OtherTargetContext otherTargetContext = new OtherTargetContext(urgentReplishmentService);
                multiFutureTasks.add(this.getMultiAndExecuteFutureTask(otherTargetContext, otherTargetGeneralQuery,unitMap));
            }
        }
        if (!CollectionUtils.isEmpty(futureTasks)) {
            for (FutureTask<OtherTargetResultDTO> itemTask : futureTasks) {
                try {
                    otherTargetResultList.add(itemTask.get());
                } catch (InterruptedException | ExecutionException e) {
                    e.printStackTrace();
                }
            }
        }
        if (!CollectionUtils.isEmpty(multiFutureTasks)) {
            for (FutureTask<List<OtherTargetResultDTO>> itemTask : multiFutureTasks) {
                try {
                    if (itemTask.get() != null) {
                        otherTargetResultList.addAll(itemTask.get());
                    }
                } catch (InterruptedException | ExecutionException e) {
                    e.printStackTrace();
                }
            }
        }
        return otherTargetResultList;
    }

    private Map<String, BigDecimal> getUnitConversion(OtherTargetGeneralQueryDTO otherTargetGeneralQuery) {
        List<String> skuList = otherTargetGeneralQuery.getSkuList();
        if (CollectionUtils.isNotEmpty(skuList)) {
            Map<String, SkuUnitDTO> skuUnitDTOMap1 = null;
            //默认必须查询出基础单位转其它单位
            if (!SkuUnitTypeEnum.BASIS_UNIT.getUnitType().equals(otherTargetGeneralQuery.getUnitType())) {
                List<UnitRateQueryDTO> unitRateQueryDTOS = new ArrayList<>();
                for (String skuCode : skuList) {
                    UnitRateQueryDTO unitRateQueryDTO = new UnitRateQueryDTO();
                    unitRateQueryDTO.setFromUnitType(SkuUnitTypeEnum.BASIS_UNIT.getUnitType());
                    unitRateQueryDTO.setToUnitType(otherTargetGeneralQuery.getUnitType());
                    unitRateQueryDTO.setSkuCode(skuCode);
                    unitRateQueryDTOS.add(unitRateQueryDTO);
                }
                skuUnitDTOMap1 = redisCacheService.getUnitConversionRatio(unitRateQueryDTOS);
            }
            Map<String, SkuUnitDTO> skuUnitDTOMap2 = null;
            //判断是否需要采购单位转非采购单位
            if (otherTargetGeneralQuery.getOtherTargetsEnum().contains(OtherTargetsEnum.BATCH_PURCHASE_ORDER_TARGET) && !SkuUnitTypeEnum.PURCHASE_UNIT.getUnitType().equals(otherTargetGeneralQuery.getUnitType())) {
                List<UnitRateQueryDTO> unitRateQueryDTOS = new ArrayList<>();
                for (String skuCode : skuList) {
                    UnitRateQueryDTO unitRateQueryDTO = new UnitRateQueryDTO();
                    unitRateQueryDTO.setFromUnitType(SkuUnitTypeEnum.PURCHASE_UNIT.getUnitType());
                    unitRateQueryDTO.setToUnitType(otherTargetGeneralQuery.getUnitType());
                    unitRateQueryDTO.setSkuCode(skuCode);
                    unitRateQueryDTOS.add(unitRateQueryDTO);
                }
                skuUnitDTOMap2 = redisCacheService.getUnitConversionRatio(unitRateQueryDTOS);
            }
            if (skuUnitDTOMap1 != null && skuUnitDTOMap2 != null) {
                skuUnitDTOMap1.putAll(skuUnitDTOMap2);
                return this.reset(skuUnitDTOMap1);
            }
            if (skuUnitDTOMap1 != null) {
                return this.reset(skuUnitDTOMap1);
            }
            return this.reset(skuUnitDTOMap2);
        }
        return null;
    }

    private Map<String, BigDecimal> reset(Map<String, SkuUnitDTO> skuUnitDTOMap1) {
        Map<String, BigDecimal> map = new HashMap<>();
        if (skuUnitDTOMap1 != null && skuUnitDTOMap1.size() > 0) {
            for (Map.Entry<String, SkuUnitDTO> item : skuUnitDTOMap1.entrySet()) {
                map.put(item.getKey(), BigDecimal.valueOf(item.getValue().getScale()));
            }
        }
        return map;
    }

    /**
     * 图表其它指标获取
     *
     * @param otherTargetGeneralQueryDTO
     * @return {@link List<OtherTargetEchartResultDTO>}
     **/
    @Override
    public List<OtherTargetEchartResultDTO> getEchartNecessaryOtherTargets(OtherTargetGeneralQueryDTO otherTargetGeneralQueryDTO) {
        List<OtherTargetEchartResultDTO> otherTargetResultList = new ArrayList<>();
        List<OtherTargetsEnum> otherTargetsEnums = otherTargetGeneralQueryDTO.getOtherTargetsEnum();
        List<FutureTask<OtherTargetEchartResultDTO>> futureTasks = new ArrayList<>();
        //批量指标
        List<FutureTask<List<OtherTargetEchartResultDTO>>> multiFutureTasks = new ArrayList<>();
        for (OtherTargetsEnum otherTargetsEnum : otherTargetsEnums) {
            if (OtherTargetsEnum.ACTUAL_SALES == otherTargetsEnum) {
                OtherTargetContext otherTargetContext = new OtherTargetContext(actualSalesQtyService);
                futureTasks.add(this.getAndExecuteEchartFutureTask(otherTargetContext, otherTargetGeneralQueryDTO));
                continue;
            }
            if (OtherTargetsEnum.REAL_TIME_STOCK == otherTargetsEnum) {
                OtherTargetContext otherTargetContext = new OtherTargetContext(realTimeStockService);
                futureTasks.add(this.getAndExecuteEchartFutureTask(otherTargetContext, otherTargetGeneralQueryDTO));
                continue;
            }
            //实际到仓库
            if (OtherTargetsEnum.ACTUAL_QTY == otherTargetsEnum) {
                OtherTargetContext otherTargetContext = new OtherTargetContext(actualQtyService);
                futureTasks.add(this.getAndExecuteEchartFutureTask(otherTargetContext, otherTargetGeneralQueryDTO));
                continue;
            }
            //实际入库
            if (OtherTargetsEnum.ACTUAL_STORAGE_QTY == otherTargetsEnum) {
                OtherTargetContext otherTargetContext = new OtherTargetContext(actualStorageQtyService);
                futureTasks.add(this.getAndExecuteEchartFutureTask(otherTargetContext, otherTargetGeneralQueryDTO));
                continue;
            }
            if (OtherTargetsEnum.BATCH_PURCHASE_ORDER_TARGET == otherTargetsEnum) {
                OtherTargetContext otherTargetContext = new OtherTargetContext(purchaseTargetService);
                multiFutureTasks.add(this.getMultiAndExecuteEchartFutureTask(otherTargetContext, otherTargetGeneralQueryDTO));
                continue;
            }
            if (OtherTargetsEnum.TI_SS_STOCK == otherTargetsEnum) {
                OtherTargetContext otherTargetContext = new OtherTargetContext(urgentReplishmentService);
                multiFutureTasks.add(this.getMultiAndExecuteEchartFutureTask(otherTargetContext, otherTargetGeneralQueryDTO));
            }
        }
        if (!CollectionUtils.isEmpty(futureTasks)) {
            for (FutureTask<OtherTargetEchartResultDTO> itemTask : futureTasks) {
                try {
                    otherTargetResultList.add(itemTask.get());
                } catch (InterruptedException | ExecutionException e) {
                    e.printStackTrace();
                }
            }
        }
        if (!CollectionUtils.isEmpty(multiFutureTasks)) {
            for (FutureTask<List<OtherTargetEchartResultDTO>> itemTask : multiFutureTasks) {
                try {
                    if (itemTask.get() != null) {
                        otherTargetResultList.addAll(itemTask.get());
                    }
                } catch (InterruptedException | ExecutionException e) {
                    e.printStackTrace();
                }
            }
        }
        return otherTargetResultList;
    }

    private FutureTask<OtherTargetResultDTO> getAndExecuteFutureTask(OtherTargetContext otherTargetContext, OtherTargetGeneralQueryDTO otherTargetGeneralQueryDTO, Map<String, BigDecimal> unitMap) {
        FutureTask<OtherTargetResultDTO> futureTask = new FutureTask<>(() -> otherTargetContext.getResult(otherTargetGeneralQueryDTO, unitMap));
        sonExecutorService.execute(futureTask);
        return futureTask;
    }

    private FutureTask<List<OtherTargetResultDTO>> getMultiAndExecuteFutureTask(OtherTargetContext otherTargetContext, OtherTargetGeneralQueryDTO otherTargetGeneralQueryDTO, Map<String, BigDecimal> unitMap) {
        FutureTask<List<OtherTargetResultDTO>> futureTask = new FutureTask<>(() -> otherTargetContext.getBatchResult(otherTargetGeneralQueryDTO, unitMap));
        sonExecutorService.execute(futureTask);
        return futureTask;
    }

    private FutureTask<OtherTargetEchartResultDTO> getAndExecuteEchartFutureTask(OtherTargetContext otherTargetContext, OtherTargetGeneralQueryDTO otherTargetGeneralQueryDTO) {
        FutureTask<OtherTargetEchartResultDTO> futureTask = new FutureTask<>(() -> otherTargetContext.getEchartResult(otherTargetGeneralQueryDTO));
        sonExecutorService.execute(futureTask);
        return futureTask;
    }

    private FutureTask<List<OtherTargetEchartResultDTO>> getMultiAndExecuteEchartFutureTask(OtherTargetContext otherTargetContext, OtherTargetGeneralQueryDTO otherTargetGeneralQueryDTO) {
        FutureTask<List<OtherTargetEchartResultDTO>> futureTask = new FutureTask<>(() -> otherTargetContext.getBatchEchartResult(otherTargetGeneralQueryDTO));
        sonExecutorService.execute(futureTask);
        return futureTask;
    }
}
